package mcps

import (
	"bytes"
	"context"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
	"net/http"
	_ "strconv"
	"time"
)

// 默认配置
const (
	DefaultWebhookURL = "https://oapi.dingtalk.com/robot/send?access_token=5316461e03a231a973c5cf882492bd91bfbcad24b4884d723b268e6a41d6a04f"
	DefaultSecret     = "SECd20d2c0163ee701adad95bb85703f2829044dfe5d2024892ff11fd76b71f79a6"
)

// DingTalkMessage 钉钉消息接口
type DingTalkMessage interface {
	ToJSON() ([]byte, error)
}

// TextMessage 文本消息
type TextMessage struct {
	Msgtype string `json:"msgtype"`
	Text    struct {
		Content string `json:"content"`
	} `json:"text"`
}

// LinkMessage 链接消息
type LinkMessage struct {
	Msgtype string `json:"msgtype"`
	Link    struct {
		Text       string `json:"text"`
		Title      string `json:"title"`
		PicURL     string `json:"picUrl,omitempty"`
		MessageURL string `json:"messageUrl"`
	} `json:"link"`
}

// MarkdownMessage Markdown消息
type MarkdownMessage struct {
	Msgtype  string `json:"msgtype"`
	Markdown struct {
		Title string `json:"title"`
		Text  string `json:"text"`
	} `json:"markdown"`
}

func (m TextMessage) ToJSON() ([]byte, error)     { return json.Marshal(m) }
func (m LinkMessage) ToJSON() ([]byte, error)     { return json.Marshal(m) }
func (m MarkdownMessage) ToJSON() ([]byte, error) { return json.Marshal(m) }

// 生成签名
func generateSign(secret string, timestamp int64) string {
	strToSign := fmt.Sprintf("%d\n%s", timestamp, secret)
	h := hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(strToSign))
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

// 发送消息到钉钉
func sendToDingTalk(webhookURL, secret string, msg DingTalkMessage) error {
	// 生成消息内容
	msgBytes, err := msg.ToJSON()
	if err != nil {
		return fmt.Errorf("消息序列化失败: %v", err)
	}

	// 处理签名
	timestamp := time.Now().UnixMilli()
	sign := ""
	if secret != "" {
		sign = generateSign(secret, timestamp)
		webhookURL = fmt.Sprintf("%s&timestamp=%d&sign=%s", webhookURL, timestamp, sign)
	}

	// 发送请求
	resp, err := http.Post(webhookURL, "application/json", bytes.NewBuffer(msgBytes))
	if err != nil {
		return fmt.Errorf("发送请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 检查响应状态
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("请求失败，状态码: %d", resp.StatusCode)
	}

	// 解析响应
	var result struct {
		Errcode int    `json:"errcode"`
		Errmsg  string `json:"errmsg"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return fmt.Errorf("解析响应失败: %v", err)
	}

	// 检查钉钉返回的错误码
	if result.Errcode != 0 {
		return fmt.Errorf("钉钉返回错误: %s", result.Errmsg)
	}

	return nil
}

func DingTalkMCPServer() {
	s := server.NewMCPServer(
		"钉钉消息发送工具",
		"1.0.0",
	)

	// 发送文本消息工具
	textMsgTool := mcp.NewTool("send_text",
		mcp.WithDescription("发送文本消息到钉钉"),
		mcp.WithString("webhook_url",
			mcp.Required(),
			mcp.Description("钉钉机器人的Webhook地址"),
		),
		mcp.WithString("secret",
			mcp.Description("安全设置的签名密钥（可选）"),
		),
		mcp.WithString("content",
			mcp.Required(),
			mcp.Description("要发送的文本内容"),
		),
	)

	// 发送链接消息工具
	linkMsgTool := mcp.NewTool("send_link",
		mcp.WithDescription("发送链接消息到钉钉"),
		mcp.WithString("webhook_url",
			mcp.Required(),
			mcp.Description("钉钉机器人的Webhook地址"),
		),
		mcp.WithString("secret",
			mcp.Description("安全设置的签名密钥（可选）"),
		),
		mcp.WithString("title",
			mcp.Required(),
			mcp.Description("消息标题"),
		),
		mcp.WithString("text",
			mcp.Required(),
			mcp.Description("消息内容"),
		),
		mcp.WithString("message_url",
			mcp.Required(),
			mcp.Description("点击消息跳转的URL"),
		),
		mcp.WithString("pic_url",
			mcp.Description("图片URL（可选）"),
		),
	)

	// 发送Markdown消息工具
	markdownMsgTool := mcp.NewTool("send_markdown",
		mcp.WithDescription("发送Markdown消息到钉钉"),
		mcp.WithString("webhook_url",
			mcp.Required(),
			mcp.Description("钉钉机器人的Webhook地址"),
		),
		mcp.WithString("secret",
			mcp.Description("安全设置的签名密钥（可选）"),
		),
		mcp.WithString("title",
			mcp.Required(),
			mcp.Description("消息标题"),
		),
		mcp.WithString("text",
			mcp.Required(),
			mcp.Description("Markdown格式的消息内容"),
		),
	)

	// 添加工具处理函数
	s.AddTool(textMsgTool, textMsgHandler)
	s.AddTool(linkMsgTool, linkMsgHandler)
	s.AddTool(markdownMsgTool, markdownMsgHandler)

	// 启动服务器
	fmt.Println("钉钉消息发送服务已启动...")
	if err := server.ServeStdio(s); err != nil {
		fmt.Printf("服务器错误: %v\n", err)
	}
}

func textMsgHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
	// 获取参数
	webhookURL := DefaultWebhookURL
	if url, ok := request.Params.Arguments["webhook_url"].(string); ok && url != "" {
		webhookURL = url
	}
	secret := DefaultSecret
	if s, ok := request.Params.Arguments["secret"].(string); ok {
		secret = s
	}
	content := request.Params.Arguments["content"].(string)

	// 构造消息
	msg := TextMessage{Msgtype: "text"}
	msg.Text.Content = content

	// 发送消息
	if err := sendToDingTalk(webhookURL, secret, msg); err != nil {
		return mcp.NewToolResultError(err.Error()), nil
	}

	return mcp.NewToolResultText("文本消息发送成功"), nil
}

func linkMsgHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
	// 获取参数
	webhookURL := DefaultWebhookURL
	if url, ok := request.Params.Arguments["webhook_url"].(string); ok && url != "" {
		webhookURL = url
	}
	secret := DefaultSecret
	if s, ok := request.Params.Arguments["secret"].(string); ok {
		secret = s
	}
	title := request.Params.Arguments["title"].(string)
	text := request.Params.Arguments["text"].(string)
	messageURL := request.Params.Arguments["message_url"].(string)
	picURL := ""
	if p, ok := request.Params.Arguments["pic_url"].(string); ok {
		picURL = p
	}

	// 构造消息
	msg := LinkMessage{Msgtype: "link"}
	msg.Link.Title = title
	msg.Link.Text = text
	msg.Link.MessageURL = messageURL
	msg.Link.PicURL = picURL

	// 发送消息
	if err := sendToDingTalk(webhookURL, secret, msg); err != nil {
		return mcp.NewToolResultError(err.Error()), nil
	}

	return mcp.NewToolResultText("链接消息发送成功"), nil
}

func markdownMsgHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
	// 获取参数
	webhookURL := DefaultWebhookURL
	if url, ok := request.Params.Arguments["webhook_url"].(string); ok && url != "" {
		webhookURL = url
	}
	secret := DefaultSecret
	if s, ok := request.Params.Arguments["secret"].(string); ok {
		secret = s
	}
	title := request.Params.Arguments["title"].(string)
	text := request.Params.Arguments["text"].(string)

	// 构造消息
	msg := MarkdownMessage{Msgtype: "markdown"}
	msg.Markdown.Title = title
	msg.Markdown.Text = text

	// 发送消息
	if err := sendToDingTalk(webhookURL, secret, msg); err != nil {
		return mcp.NewToolResultError(err.Error()), nil
	}

	return mcp.NewToolResultText("Markdown消息发送成功"), nil
}
